package cac.fenjian.resource.common;



import com.cac.dme.adapter.rest.client.RestClient;
import com.cac.dme.adapter.rest.msg.ResponseMsg;
import com.cac.dme.common.exception.service.RestException;
import com.cac.dme.core.context.RequestContextHolder;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Repository;
import org.springframework.util.StringUtils;

import java.util.List;
import java.util.Map;

/**
 * @program test-curd
 * @description 接口调用工具类
 * @author: LSL
 * @create: 2022-07-12-10-34
 **/

/**
 * 使用静态方法调用rest client，实现接口调用
 */
@Repository
public class RestUtil {


    private static RestClient restClient;

    private static final ObjectMapper mapper = new ObjectMapper();

    //提供setter方法供外部注入
    public static void setRestClient(RestClient restClient) {
        RestUtil.restClient = restClient;
    }

    /**
     * POST方法根据传入typeReference类型返回对应的对象
     * 此方法适用于返回带泛型的对象
     * RestUtil.callServicePost(url, serviceName, yfkjOpDTOS, new ParameterizedTypeReference<ResponseMsg<List<TFoAllDTO>>>() {}
     */
    public static <T> T callServicePost(String uri, String serviceName, Object obj, ParameterizedTypeReference<T> typeReference) {
        HttpHeaders httpHeaders = getHttpHeaders();
        System.out.println(typeReference+"typeReference");
        System.out.println(obj+"obj");
        System.out.println(uri+"uri");
        System.out.println(serviceName+"serviceName");
        System.out.println(httpHeaders+"httpHeaders");
        return restClient.doPost(serviceName, uri, obj, typeReference, httpHeaders);
    }

    /**
     * POST方法根据传入typeReference类型返回对应的对象
     * 此方法适用于返回带泛型的对象
     * RestUtil.callServicePost(url, serviceName, yfkjOpDTOS, new ParameterizedTypeReference<ResponseMsg<List<TFoAllDTO>>>() {}
     */
    public static <T> T callServicePost(String uri, String serviceName, Object obj, ParameterizedTypeReference<T> typeReference, HttpHeaders httpHeaders) {
        return restClient.doPost(serviceName, uri, obj, typeReference, httpHeaders);
    }

    /**
     * 传入返回类型对象，而非ParameterizedTypeReference
     * 注意：当传入的typeObject本身就是带泛型的，如List<String>、Map<String,object>等，泛型类型可能不会生效。
     * 需要完整泛型信息传入ParameterizedTypeReference对象
     * 注意：发现此方法有bug，泛型并不会获取到。使用下面的方法代替
     */
    @Deprecated
    public static <T> T callServicePost(String uri, String serviceName, Object obj, T typeObject) {
        ParameterizedTypeReference<ResponseMsg<T>> typeReference = new ParameterizedTypeReference<ResponseMsg<T>>() {
        };
        ResponseMsg<T> msg = callServicePost(uri, serviceName, obj, typeReference);
        if (!"200".equals(msg.getRetCode())) {
            throw new RestException(serviceName + uri + "服务调用异常,错误代码:" + msg.getRetCode() + ",错误原因:" + msg.getMessage());
        }
        return msg.getResponseBody();
    }

    /**
     * @param uri         请求路径
     * @param serviceName 服务名
     * @param obj         请求体
     * @param clazz       返回类型Class对象
     * @param <T>         泛型，需要返回的类型
     * @return 请求返回值
     */
    public static <T> T callServicePost(String uri, String serviceName, Object obj, Class<T> clazz) {
        JavaType type = mapper.getTypeFactory().constructParametricType(ResponseMsg.class, clazz);
        ParameterizedTypeReference<ResponseMsg<T>> typeReference = ParameterizedTypeReference.forType(type);
        ResponseMsg<T> msg = callServicePost(uri, serviceName, obj, typeReference);
        if (!"200".equals(msg.getRetCode())) {
            throw new RestException(serviceName + uri + "服务调用异常,错误代码:" + msg.getRetCode() + ",错误原因:" + msg.getMessage());
        }
        return msg.getResponseBody();
    }

    public static <T> List<T> callServicePostForList(String uri, String serviceName, Object obj, Class<T> clazz) {
        JavaType inner = mapper.getTypeFactory().constructParametricType(List.class, clazz);
        JavaType type = mapper.getTypeFactory().constructParametricType(ResponseMsg.class, inner);
        ParameterizedTypeReference<ResponseMsg<List<T>>> typeReference = ParameterizedTypeReference.forType(type);
        ResponseMsg<List<T>> msg = callServicePost(uri, serviceName, obj, typeReference);
        if (!"200".equals(msg.getRetCode())) {
            throw new RestException(serviceName + uri + "服务调用异常,错误代码:" + msg.getRetCode() + ",错误原因:" + msg.getMessage());
        }
        return msg.getResponseBody();
    }

    public static <T, U> Map<T, U> callServicePostForMap(String uri, String serviceName, Object obj, Class<T> key, Class<U> value) {
        JavaType inner = mapper.getTypeFactory().constructParametricType(Map.class, key, value);
        JavaType type = mapper.getTypeFactory().constructParametricType(ResponseMsg.class, inner);
        ParameterizedTypeReference<ResponseMsg<Map<T, U>>> typeReference = ParameterizedTypeReference.forType(type);
        ResponseMsg<Map<T, U>> msg = callServicePost(uri, serviceName, obj, typeReference);
        if (!"200".equals(msg.getRetCode())) {
            throw new RestException(serviceName + uri + "服务调用异常,错误代码:" + msg.getRetCode() + ",错误原因:" + msg.getMessage());
        }
        return msg.getResponseBody();
    }

    public static <T> ResponseMsg<T> callServicePostReturnResponseMsg(String uri, String serviceName, Object obj, Class<T> clazz) {
        JavaType type = mapper.getTypeFactory().constructParametricType(ResponseMsg.class, clazz);
        ParameterizedTypeReference<ResponseMsg<T>> typeReference = ParameterizedTypeReference.forType(type);
        return callServicePost(uri, serviceName, obj, typeReference);
    }

    /**
     * uri 调用uri
     * serviceName 调用的服务名
     * <p>
     * return String 响应
     */
    public static String callServiceGet(String uri, String serviceName) {
        ParameterizedTypeReference<String> typeReference = new ParameterizedTypeReference<String>() {
        };
        return callServiceGet(uri, serviceName, typeReference);
    }

    public static <T> T callServiceGet(String uri, String serviceName, T resultObject) {
        ParameterizedTypeReference<T> typeReference = new ParameterizedTypeReference<T>() {
        };
        return callServiceGet(uri, serviceName, typeReference);
    }

    public static <T> T callServiceGet(String uri, String serviceName, ParameterizedTypeReference<T> typeReference) {
        HttpHeaders httpHeaders = getHttpHeaders();
        return restClient.doGet(serviceName, uri, typeReference, httpHeaders);
    }

    //获取带有token的HttpHeaders对象
    private static HttpHeaders getHttpHeaders() {
        HttpHeaders httpHeaders = new HttpHeaders();
        String xToken = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJBcHDliY3nq6_mjojmnYMiLCJhdWQiOiIxIiwiQVBQX0lEIjoiMSIsIkxBTkdVQUdFX0NPREUiOiJ6aF9DTiIsIm5iZiI6MTU5NDEwOTI4NSwiaXNzIjoiQVZJQy1ESUdJVEFMIiwiZXhwIjozMTcxOTQ2MDk1LCJPUkdfSURFTlRJVFkiOiJPUkdfUk9PVCIsIlVTRVJfREVQVF9JRCI6IjEiLCJpYXQiOjE1OTQxMDkyODUsImp0aSI6IjY1MGFlNDU1LWE0OWEtNGVkYi1hODhlLThhODAwZGRmNmMwZiJ9.cL7yCcN04i3pCGCTsZ9gZMAhrX21kjQbAlX34RzPMXg";
        httpHeaders.add("X-Access-Token", xToken);
        String token = RequestContextHolder.getToken();
        if (StringUtils.isEmpty(token)) {
            //若当前会话中找不到token，调用其他服务的时候使用永久token
            token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJDRjExMDAiLCJ1c2VyTmFtZSI6ImNlc2hpIiwiZXhwIjoxNjQ0ODIxNTgwLCJ1c2VyQ29kZSI6IkNGMTEwMCJ9.93PruZIX-jKyS9nMNTbkZIEFxVdZzxgzir8Mdp_MjQw";
        }
        httpHeaders.add("token", token);
        return httpHeaders;
    }
}
